/**
 * *****************************************************************************
 * Copyright (c) 2011 GigaSpaces Technologies Ltd. All rights reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 * *****************************************************************************
 */
package com.kedacom.demo.sigar.cloudify;

import com.kedacom.demo.sigar.util.SigarUtil;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;

/**
 * ********
 * The default process killer implementation, which uses SIGAR to kill
 * processes.
 *
 * @author barakme
 *
 */
public class DefaultProcessKiller implements ProcessKiller {

    private static final int POST_KILL_SLEEP_INTERVAL = 100;
    private static final int PROCESS_STATUS_CHECK_INTERVAL = 200;
    private static final int PROCESS_STATUS_CHECK_ATTEMPTS = 5;
    private static java.util.logging.Logger logger =
            java.util.logging.Logger.getLogger(DefaultProcessKiller.class.getName());
    private int killRetries = 2;

    @Override
    public void killProcess(final long pid)
            throws USMException {
        if (pid == 0) {
            return; // this is possible in some end case situations, in the
            // IntegratedProcessingUnitContainer
        }
        final Sigar sigar = SigarUtil.getSigarInstance();

        for (int retries = 0; retries <= killRetries; ++retries) {
            try {
                logger.info("Killing process: " + pid);
                sigar.kill(pid, "SIGTERM"); // (9 is the only signal used for
                // Kill on windows)
            }
            catch (final SigarException e) {
                logger.warning("Failed to shut down process: " + pid + ". Process may already be dead. Error was: "
                        + e.getMessage() + ".");
            }

            try {
                // sleep for a short period so process table get cleaned up
                Thread.sleep(POST_KILL_SLEEP_INTERVAL);
            }
            catch (final InterruptedException e1) {
                // ignore
            }

            // wait until process dies
            for (int i = 0; i < PROCESS_STATUS_CHECK_ATTEMPTS; ++i) {
                if (!USMUtils.isProcessAlive(pid)) {
                    logger.info("Process " + pid + " is dead");
                    return;
                }
                try {
                    Thread.sleep(PROCESS_STATUS_CHECK_INTERVAL);
                }
                catch (final InterruptedException e) {
                    // ignore
                }
            }
            logger.warning("Attempt number " + (retries + 1) + " to kill process " + pid + " failed.");
        }

        logger.severe("Process " + pid + " did not die as expected!");

        throw new USMException("Attempt to kill process " + pid + " failed!");

    }

    public int getKillRetries() {
        return killRetries;
    }

    public void setKillRetries(final int killRetries) {
        this.killRetries = killRetries;
    }
}
